import AsyncStorage from '@react-native-community/async-storage';
import { filter, equals, forEach, clone } from 'ramda';

import { DownloadVideoObject, SortedDownloadVideos } from './types';
import tracker from '../../util/actionTracker';
import { handleStoreVideoFailed } from '../../constant/events';
// 视频缓存队列
const STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE = 'downloadVideoQueue';

// 视频缓存清晰度
const STORAGE_KEY_VIDEO_DOWNLOAD_RESOLUTION = 'videoDownloadResolution';

// 仅WIFI下载
const STORAGE_KEY_ONLY_WIFI_DOWNLOAD = 'onlyWifiDownload';

let videoQueue: DownloadVideoObject[] = [];

let userLessonResourceIds: number[] = [];

enum HANDLE_VIDEO_QUEUE_TYPE {
  SetDlVideo = 1,
  UnshiftDlVideoQueue,
  DeleteDlVideo
}

export const emptyVideoItem = {
  id: 0, // id
  title: '', // title
  type: 0, // 视频type -ld -sd -hd
  url: '', // m3u8的url
  size: 0, // 预计总文件大小
  serverDir: '', // 服务器路径 -m3u8和ts文件所在目录
  folderName: '', // 本地创建文件夹名 -与m3u8同名 -eg: c1c102cbf2ae973811c782720d49120e
  tsList: [], // ts文件列表
  keyUrl: '', // 密钥地址
  progress: 0, // 总下载进度
  indexHasDone: false, // m3u8索引是否下载完成
  keyHasDone: false, // 密钥是否下载完成
  m3u8Path: '', // 本地m3u8路径
  parentId: 0, // 父级id
  parentTitle: '', // 父级title
  isPaused: false, // 是否暂停
  isFailed: false, // 是否失败
  startTime: '', // 下载开始时间
  continueTime: new Date(), // 下载继续时间
  duration: 0, // 下载时间
  source: '' // 视频来源
};

export const emptySortedDownloadVideos: SortedDownloadVideos = {
  parentId: 0,
  parentTitle: '',
  totalSize: 0,
  progress: 0,
  source: '',
  videos: [],
  isPaused: false, // 是否暂停
  isFailed: false // 是否失败
};

AsyncStorage.getItem(STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE).then(
  (res: any): void => {
    if (res) {
      videoQueue = JSON.parse(res) || [];
    }
  }
);

// 设置当前用户拥有的lessonResourceIds
export const setUserLessonResourceIds = (data: number[]): void => {
  userLessonResourceIds = data;
};

const filterUserDownloadQueue = (): DownloadVideoObject[] => {
  if (userLessonResourceIds.length === 0) return videoQueue;

  const filterVideoQueue = videoQueue.filter((item): boolean =>
    userLessonResourceIds.includes(item.parentId)
  );
  return filterVideoQueue;
};

// 设置某项视频缓存信息
export const setDlVideo = (data: Partial<DownloadVideoObject>): void => {
  const { id = 0, downloadQueue, tsSuccessSubscription, ...otherData } = data;
  if (id) {
    const index = videoQueue.findIndex((item): boolean => item.id === id);
    if (index !== -1) {
      videoQueue[index] = { ...videoQueue[index], ...otherData, id };
    } else {
      videoQueue.push({ ...emptyVideoItem, ...otherData, id });
    }

    try {
      AsyncStorage.setItem(
        STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE,
        JSON.stringify(videoQueue)
      );
    } catch (error) {
      tracker.reportAction(handleStoreVideoFailed, {
        reason: JSON.stringify({
          type: HANDLE_VIDEO_QUEUE_TYPE.SetDlVideo,
          error
        })
      });
      AsyncStorage.setItem(
        STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE,
        JSON.stringify(videoQueue)
      );
    }
  }
};

// 从头插入视频缓存队列
export const unshiftDlVideoQueue = (
  data: Partial<DownloadVideoObject>
): void => {
  const { id = 0, ...otherData } = data;
  if (id) {
    const index = videoQueue.findIndex((item): boolean => item.id === id);
    if (index !== -1) {
      videoQueue.splice(index, 1);
    }

    videoQueue.unshift({ ...emptyVideoItem, ...otherData, id });

    try {
      AsyncStorage.setItem(
        STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE,
        JSON.stringify(videoQueue)
      );
    } catch (error) {
      tracker.reportAction(handleStoreVideoFailed, {
        reason: JSON.stringify({
          type: HANDLE_VIDEO_QUEUE_TYPE.UnshiftDlVideoQueue,
          error
        })
      });
      AsyncStorage.setItem(
        STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE,
        JSON.stringify(videoQueue)
      );
    }
  }
};

// 获取全部
export const getAllDlVideos = (): DownloadVideoObject[] => {
  return filterUserDownloadQueue();
};

// 获取未完成
export const getUnFinishedVideos = (): DownloadVideoObject[] => {
  return filterUserDownloadQueue().filter((item): boolean => {
    const { indexHasDone, keyHasDone, tsList } = item;
    const tsHaveDone = tsList.every((ts): boolean => ts.hasDone);
    return !indexHasDone || !keyHasDone || !tsHaveDone;
  });
};

// 获取下载完成
export const getFinishedVideos = (): DownloadVideoObject[] => {
  const finishedVideos: DownloadVideoObject[] = [];

  filterUserDownloadQueue().forEach((item): void => {
    const { indexHasDone, keyHasDone, tsList } = item;
    const tsHaveDone = tsList.every((ts): boolean => ts.hasDone);
    if (tsHaveDone && indexHasDone && keyHasDone) {
      finishedVideos.unshift(item);
    }
  });

  return finishedVideos;
};

// 获取某个视频
export const getDlVideo = (
  id: number | string
): DownloadVideoObject | undefined => {
  const dlVideo = filterUserDownloadQueue().find(
    (item): boolean => item.id === id
  );
  return dlVideo;
};

// 获取某个视频
export const getDlVideoByFolderName = (
  folderName: string
): DownloadVideoObject | undefined => {
  const dlVideo = filterUserDownloadQueue().find(
    (item): boolean => item.folderName === folderName
  );
  return dlVideo;
};

// 获取最近的下载视频
export const getLatestDlVideo = (): DownloadVideoObject | undefined => {
  const dlVideo = filterUserDownloadQueue().find((item): boolean => {
    const { indexHasDone, keyHasDone, tsList, isPaused, isFailed } = item;
    const tsHaveDone = tsList.every((ts): boolean => ts.hasDone);
    return (
      (!indexHasDone || !keyHasDone || !tsHaveDone) && !isPaused && !isFailed
    );
  });
  return dlVideo;
};

// 将下载完成的项移到队列最末
export const moveToEnd = (id: number | string): void => {
  const index = videoQueue.findIndex((item): boolean => item.id === id);
  if (index !== -1) {
    const movingVideo = videoQueue.splice(index, 1);
    videoQueue.push(movingVideo[0]);
    AsyncStorage.setItem(
      STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE,
      JSON.stringify(videoQueue)
    );
  }
};

// 删除全部
export const deleteAllDlVideos = (): void => {
  videoQueue = [];
  AsyncStorage.removeItem(STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE);
};

// 删除某项
export const deleteDlVideo = (id: number | string): void => {
  try {
    const index = videoQueue.findIndex((item): boolean => item.id === id);
    if (index !== -1) {
      videoQueue.splice(index, 1);
      AsyncStorage.setItem(
        STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE,
        JSON.stringify(videoQueue)
      );
    }
  } catch (error) {
    deleteAllDlVideos();
    tracker.reportAction(handleStoreVideoFailed, {
      reason: JSON.stringify({
        type: HANDLE_VIDEO_QUEUE_TYPE.DeleteDlVideo,
        error
      })
    });
  }
};

// 获取某个parentId的视频
export const getSortedDlVideo = (
  expectParentId: number
): SortedDownloadVideos => {
  const allVideos = getAllDlVideos();
  let sortedDlVideo = {
    ...emptySortedDownloadVideos,
    parentId: expectParentId
  };

  allVideos.forEach((item): void => {
    const { parentId, parentTitle, source } = item;

    if (parentId !== expectParentId) {
      return;
    }
    if (sortedDlVideo.videos.length === 0) {
      sortedDlVideo = {
        ...sortedDlVideo,
        parentTitle,
        source,
        progress: 0,
        totalSize: item.size,
        videos: [item]
      };
    } else {
      sortedDlVideo.videos.unshift(item);
      sortedDlVideo = {
        ...sortedDlVideo,
        totalSize: sortedDlVideo.totalSize + item.size
      };
    }
  });

  let downloadedSize = 0;
  const { videos, totalSize } = sortedDlVideo;
  videos.forEach((video): void => {
    downloadedSize += video.progress * video.size;
  });

  sortedDlVideo.progress = downloadedSize / totalSize;
  sortedDlVideo.isPaused = videos.every((item): boolean => item.isPaused);
  sortedDlVideo.isFailed = videos.some((item): boolean => item.isFailed);

  return sortedDlVideo;
};

// 获取归类列表
export const getSortedDlVideosList = (): SortedDownloadVideos[] => {
  const allVideos = getAllDlVideos();
  const sortedVideos: SortedDownloadVideos[] = [];

  allVideos.forEach((item): void => {
    const { parentId, parentTitle, source } = item;
    const index = sortedVideos.findIndex(
      (videos): boolean => videos.parentId === parentId
    );
    if (index === -1 || parentId === 0) {
      sortedVideos.push({
        parentId,
        parentTitle,
        progress: 0,
        source,
        totalSize: item.size,
        videos: [item],
        isPaused: false,
        isFailed: false
      });
    } else {
      sortedVideos[index].videos.unshift(item);
      sortedVideos[index] = {
        ...sortedVideos[index],
        totalSize: sortedVideos[index].totalSize + item.size
      };
    }
  });

  sortedVideos.forEach(({ videos, totalSize }, index): void => {
    let downloadedSize = 0;
    videos.forEach((video): void => {
      downloadedSize += video.progress * video.size;
    });
    sortedVideos[index].progress = downloadedSize / totalSize;
    sortedVideos[index].isPaused = videos.every(
      (item): boolean => item.isPaused
    );
    sortedVideos[index].isFailed = videos.some(
      (item): boolean => item.isFailed
    );
  });

  return sortedVideos;
};

let onlyWifiDownload: { [key: string]: boolean } = {}; // 仅wifi下载
AsyncStorage.getItem(STORAGE_KEY_ONLY_WIFI_DOWNLOAD).then((res: any): void => {
  if (res) {
    onlyWifiDownload = JSON.parse(res);
  }
});

export const setOnlyWifiDownload = (userId: string, value: boolean): void => {
  onlyWifiDownload[userId] = value;
  AsyncStorage.setItem(
    STORAGE_KEY_ONLY_WIFI_DOWNLOAD,
    JSON.stringify(onlyWifiDownload)
  );
};

export const getOnlyWifiDownload = (userId: string): boolean => {
  // return onlyWifiDownload[userId] === undefined
  //   ? true
  //   : onlyWifiDownload[userId];
  return false;
};

export const getVideoIsFinished = (id: number | string): boolean => {
  let isFinished = false;
  const video = getDlVideo(id);
  if (video) {
    const { tsList, indexHasDone, keyHasDone } = video;
    const tsHaveDone = tsList.every((ts): boolean => ts.hasDone);
    isFinished = tsHaveDone && indexHasDone && keyHasDone;
  }
  return isFinished;
};

export const getVideosByParentId = (
  parentId: number
): { [key: string]: DownloadVideoObject } => {
  const filterByParentId = (item: DownloadVideoObject): boolean =>
    equals(item.parentId)(parentId);

  const videos = filter(filterByParentId)(filterUserDownloadQueue());

  const videosObject: { [key: string]: DownloadVideoObject } = {};

  forEach((item: DownloadVideoObject): void => {
    videosObject[String(item.id)] = item;
  })(videos);

  return videosObject;
};

export const compressDownloadQueue = (): void => {
  videoQueue.forEach(({ id, parentId }, index): void => {
    if (getVideoIsFinished(id)) {
      videoQueue[index].tsList = [];
    }
  });
  AsyncStorage.setItem(
    STORAGE_KEY_DOWNLOAD_VIDEO_QUEUE,
    JSON.stringify(videoQueue)
  );
};
